import threading
import queue


class factory:
    def __init__(self, frame_reader, worker, frame_writer, threads=2):
        self.reader = frame_reader
        self.writer = frame_writer
        self.worker = worker
        self.threads = threads
        self.queue_ins = [queue.Queue(3)] * self.threads
        self.queue_outs = [queue.Queue(3)] * self.threads

    def run(self):
        produce = threading.Thread(target=self.distributor)
        produce.run()
        pool = [threading.Thread(target=self.employee, args=(
            self.queue_ins[i], self.queue_outs[i])) for i in range(self.threads)]
        for elemt in pool:
            elemt.run()
        consume = threading.Thread(target=self.collector)
        consume.setDaemon(True)
        consume.run()

    def employee(self, queue_in, queue_out):
        assert isinstance(queue_in, queue.Queue)
        assert isinstance(queue_out, queue.Queue)
        while True:
            frame_in = queue_in.get()
            if frame_in != None:
                queue_out.put(self.worker(frame_in))
            else:
                queue_out.put(None)
                break

    def distributor(self):
        ring_itor = 0
        while True:
            self.queue_ins[ring_itor].put(next(self.reader))
            ring_itor += 1
            ring_itor %= self.threads

    def collector(self):
        ring_itor = 0
        while True:
            frame_out=self.queue_outs[ring_itor].get()
            if frame_out != None:
                self.writer.send(frame_out)
            else :
                break
            ring_itor += 1
            ring_itor %= self.threads
